/* Gyroe 1.0.0 */
/* fe_error.c : Handles warning and error printing
   for fe files. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fe_shared.h"
#include "fe_error.h"

void init_error()
{
    warning_list = malloc(8 * sizeof(char *));
    warning_list_extra = 8; warning_list_pos = -1;
}

void init_error_cache()
{
    error_cache = malloc(8 * sizeof(char *));
    error_cache_extra = 8; error_cache_pos = -1;
}

static boolean find_warning(char *str)
{
    int i;

    for (i = 0;i <= warning_list_pos;i++) {
        if (strcmp(warning_list[i], str))
            return 1;
    }
    return 0;
}

void add_warning(char *msg)
{
    if (OpWarning_called) {
        /* 'Warning : ' and '\n' will have already been added.
           Don't search if nothing's there. */
        if (warning_list_pos > 0) {
            /* Make sure this isn't a repeat. */
            if (find_warning(msg))
                return;
        }

        warning_list_extra--; warning_list_pos++;
        if (warning_list_extra == -1) {
            warning_list = (char **)realloc(warning_list, (warning_list_pos+8)
                           * sizeof (char));
            warning_list_extra = 7;
        }

        warning_list[warning_list_pos] = malloc(strlen(msg) + 1 * sizeof(char));
        strcpy(warning_list[warning_list_pos], msg);
    }
}

static void show_warnings(int errfile)
{
    int c, i;

    if (OpWarning_called && warning_list_pos > 0) {
        for (i = 0;i <= warning_list_pos;i++) {
            if (errfile == 1) {
                fputs(warning_list[i], stderr);

                if (!(i % 20)) {
                    fputs("\nPress Enter to continue, q to quit.", stderr);

                    c = getchar();
                    if (c == 'q')
                        break;
                    else if (c == '\n')
                        continue;
                }
            }
            else
                fputs(warning_list[i], TempErrFile);
        }
    }
}

static void open_error_file()
{
    TempErrFile = fopen("ex.err", "w");

    if (TempErrFile == NULL) {
        fputs("Can't create error message file : ex.err\n", stderr);
        shutdown_gyroe(0);
    }
}

static void show_errors(FILE *out)
{
    int i, j, k, l;

    if (thisline[1] == GY_EOF) {
        fputs("<end-of-file>", out);
        return;
    }
    else {
        /* J.A. -> This is the only way i've been able to print thisline. */
        i = 0;
        while (1) {
            if (thisline[i] == '\0')
                break;
            fprintf(out, "%c", thisline[i]);
            i++;
        }
    }

    /* First, determine the length of the bad token.
       bp-1 will be the last part of the token so, backtrack
       until whitespace or beginning of line is found. */
    for (j = bp-1, k = 0;j > 0;j--, k++) {
        if (thisline[j] == '\t' || thisline[j] == ' ')
            break;
    }
    /* Print out the whitespace leading up to the token. If a tab is above,
       print a tab below. For all others, print a space. This is done to ensure
       the ^ characters will print correctly under the token. */
    if (j - k) {
        for (l = 0;l <= j;l++) {
            if (thisline[i] == '\t')
                fputs("\t", out);
            else
                fputs(" ", out);
        }
    }
    /* Finally, print out the ^ marks. */
    for (l = j-k;l < j;l++)
        fputs("^", out);

    fputs("\n\n", out);
}

void compile_error(char *msg)
{
    /* Print offending line, line_number, and the message.
       Do to stderr first, in case ex.err fails to open. */

    fprintf(stderr, "%s:%d\n%s\n", user_files[current_file_no], line_number, msg);
    show_errors(stderr);
    show_warnings(1); /* STDERR */

    /* Put a copy into ex.err. */
    open_error_file();
    fprintf(TempErrFile, "%s:%d\n%s\n", user_files[current_file_no], line_number, msg);
    show_errors(TempErrFile);

    show_warnings(2); /* TempErrFile */
    fclose(TempErrFile);

    shutdown_gyroe(0);
}

void syntax_error(char *msg)
{
    if (!error_caught) {
        init_error_cache();
        error_caught = 1;
    }

    error_cache_extra--; error_cache_pos++;
    if (error_cache_extra = -1) {
        error_cache = (char **)realloc(error_cache, (error_cache_pos+8) * sizeof (char *));
        error_cache_extra = 7;
    }

    error_cache[error_cache_pos] = malloc(strlen(msg) + 1 * sizeof(char));
    strcpy(error_cache[error_cache_pos], msg);
}

void internal_error(char *msg)
{
    /* Rare case - Internal error somewhere. Report file, line, and the message. */
    fprintf(stderr, "Internal Error at %s:%d - %s\n", user_files[current_file_no], line_number, msg);
    shutdown_gyroe(0);
}

